//
//  ZFRealmManager.swift
//  map
//
//  Created by fyzq on 2024/1/30.
//

import UIKit
import RealmSwift

// 事件闭包(做完Realm操作后的事件)
public typealias RealmDoneTask = () -> Void
class ZFRealmManager: NSObject {

    /// 单利
    static let shared = ZFRealmManager()
    private override init() {
        super.init()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    /// 当前的 Realm
     var realm: Realm?
    
    static var fileURL: URL? {
        return shared.realm?.configuration.fileURL
    }
    /// 当前的版本号
    fileprivate var schemaVersion: UInt64 = 0
    /// 当前的加密字符串
    fileprivate var keyWord: String? = ""
    
    
}
extension ZFRealmManager {
    
    static func configRealm(userID: String?,keyWord: String? = nil, schemaVersion: UInt64 = 0,migrationBlock: MigrationBlock? = nil){
        
        /// 找到沙盒路径 这里是Document
        var fileURL = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,true).first!
        fileURL += "/\(userID  ?? "")default.realm"
              
        
        let config =   Realm.Configuration(fileURL: URL.init(string: fileURL),schemaVersion: schemaVersion) { migration, oldSchemaVersion in
            // 进行数据迁移，因此 oldSchemaVersion == 0
            if oldSchemaVersion < 1 {
                // 什么都不要做！Realm 会自行检测新增和需要移除的属性，然后自动更新硬盘上的数据库架构
            }
            // 低版本的数据库迁移......
            if migrationBlock != nil {
                migrationBlock!(migration, oldSchemaVersion)
            }
        }
        
        Realm.Configuration.defaultConfiguration = config
        guard let realm = try? Realm(configuration: config) else {
            return
        }
        shared.schemaVersion = schemaVersion
        shared.realm = realm
        shared.keyWord = keyWord
        
//        print(realm.configuration.fileURL)
    }
    
    // MARK: 删除当前的realm库
    /// 删除当前的realm库
    @discardableResult
    static func deleteRealmFiles() -> Bool {
        let realmURL = shared.realm?.configuration.fileURL ?? Realm.Configuration.defaultConfiguration.fileURL!
        let realmURLs = [
            realmURL,
            realmURL.appendingPathExtension("lock"),
            realmURL.appendingPathExtension("management")
        ]
        for URL in realmURLs {
            do {
                try FileManager.default.removeItem(at: URL)
                self.configRealm(userID: nil, keyWord: shared.keyWord, schemaVersion: shared.schemaVersion)
            } catch {
                // handle error
                return false
            }
        }
        return true
    }
}


extension ZFRealmManager {
    
    // MARK: 添加单个对象
    /// 添加单个对象
    /// - Parameters:
    /// - object: 对象
    /// - update: 是否更新
    /// - task: 添加后操作
    static func add(_ object: Object, update: Realm.UpdatePolicy = .error, task: @escaping RealmDoneTask) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            realm.add(object, update: update)
            task()
        }
    }
    // MARK: 添加多个对象
    /// 添加多个对象
    /// - Parameters:
    ///   - objects: 对象组
    ///   - update: 是否更新
    ///   - task: 添加后操作
    static func addList(_ objects: Array<Object>, update: Realm.UpdatePolicy = .error, task: @escaping RealmDoneTask) {
        guard let realm = shared.realm else {
            return
        }
//        realm.beginWrite()
        try? realm.write {
            realm.add(objects, update: update)
            task()
        }
    }
    
}

extension ZFRealmManager {
    
    // MARK: 在事务中删除一个对象
    /// 在事务中删除一个对象
    /// - Parameters:
    ///   - object: 单个被删除的对象
    ///   - task: 删除后操作
    static func delete(_ object: Object, task: @escaping RealmDoneTask) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            realm.delete(object)
            task()
        }
    }
    
    // MARK: 在事务中删除多个对象
    /// 在事务中删除多个对象
    /// - Parameters:
    ///   - objects: 多个要被删除的对象
    ///   - task: 删除后操作
    static func deleteList(_ objects: Array<Object>, task: @escaping RealmDoneTask) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            realm.delete(objects)
            task()
        }
    }
    
    // MARK: 删除所有数据（不要轻易调用）
    /// 从 Realm 中删除所有数据
    /// - Parameter task: 删除后操作
    static func deleteAll(task: @escaping RealmDoneTask) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            realm.deleteAll()
            task()
        }
    }
    
    // MARK: 根据条件删除对象
    /// 根据条件删除对象
    /// - Parameters:
    ///   - object: 对象类型
    ///   - predicate: 条件
    static func deleteByPredicate(object: Object.Type, predicate: NSPredicate) {
        guard let results: Array<Object> = objectsWithPredicate(object: object, predicate: predicate) else {
            return
        }
        deleteList(results) {
        }
    }
}

// MARK:- 改
extension ZFRealmManager{
    // MARK: 更改某个对象（根据主键存在来更新，元素必须有主键）
    /// 更改某个对象（根据主键存在来更新）
    /// - Parameters:
    ///   - object: 某个对象
    ///   - update: 是否更新
    static func update(object: Object, update: Realm.UpdatePolicy = .modified) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            realm.add(object, update: update)
        }
    }

    // MARK: 更改多个对象（根据主键存在来更新，元素必须有主键）
    /// 更改多个对象（根据主键存在来更新）
    /// - Parameters:
    ///   - objects: 多个对象
    ///   - update: 是否更新
    static func updateList(objects: Array<Object>, update: Realm.UpdatePolicy = .modified) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            realm.add(objects, update: .modified)
        }
    }
    
    // MARK: 更新操作，对于realm搜索结果集当中的元素，在action当中直接赋值即可修改(比如查询到的某些属性可直接修改)
    /// 更新操作，对于realm搜索结果集当中的元素，在action当中直接赋值即可修改
    /// - Parameter action: 操作
    static func updateWithTranstion(action: (Bool) -> Void) {
        guard let realm = shared.realm else {
            return
        }
        try? realm.write {
            action(true)
        }
    }
    
    // MARK: 更新一个一个对象的多个属性值（根据主键存在来更新，元素必须有主键）
    /// 更新一个一个对象的多个属性值
    /// - Parameters:
    ///   - object: 对象类型
    ///   - value: 数组数组
    ///   - update: 更新类型
    static func updateObjectAttribute(object: Object.Type, value: Any = [:], update: Realm.UpdatePolicy = .modified) {
        guard let realm = shared.realm else {
            return
        }
        do {
            try realm.write {
                realm.create(object, value: value, update: update)
            }
        } catch _ {
            
        }
    }
    
}


extension ZFRealmManager{
    // MARK: 查询某个对象数据
    /// 查询某个对象数据
    /// - Parameter type: 对象类型
    /// - Returns: 返回查询的结果
    static func objects(_ object: Object.Type) -> [Object]? {
        guard let results = queryWithType(object: object) else {
            return nil
        }
        return resultsToObjectList(results: results)
    }
    
    static func object(_ object: Object.Type) ->  Results<Object>?{
        
        guard let realm = shared.realm else {
            return nil
        }
        return realm.objects(object);
    }
    
    // MARK: 查询某个对象数据(根据条件)
    /// 查询某个对象数据(根据条件)
    /// - Parameters:
    ///   - object: 对象类型
    ///   - predicate: 查询条件
    /// - Returns: 返回查询结果
    static func objectsWithPredicate(object: Object.Type, predicate: NSPredicate) -> Array<Object>? {
        guard let results = queryWith(object: object, predicate: predicate) else {
            return nil
        }
        return resultsToObjectList(results: results)
    }
    
    // MARK: 带排序条件查询
    ///  带排序条件查询
    /// - Parameters:
    ///   - object: 对象类型
    ///   - predicate:  查询条件
    ///   - sortedKey: 排序的键
    ///   - isAssending: 升序还是降序，默认升序
    /// - Returns: 返回查询对象数组
    static func objectsWithPredicateAndSorted(object: Object.Type,
                                           predicate: NSPredicate,
                                           sortedKey: String,
                                         isAssending: Bool = true) -> Array<Object>? {
        guard let results = queryWithSorted(object: object, predicate: predicate, sortedKey: sortedKey, isAssending: isAssending) else {
            return nil
        }
        return resultsToObjectList(results: results)
    }
    
    // MARK: 带分页的查询
    /// 带分页的查询
    /// - Parameters:
    ///   - object: 对象类型
    ///   - predicate: 查询条件
    ///   - sortedKey: 排序的键
    ///   - isAssending: 升序还是降序，默认升序
    ///   - fromIndex: 起始页
    ///   - pageSize: 一页的数量
    /// - Returns: 返回查询对象数组
    static func objectsWithPredicateAndSortedForPages(object: Object.Type,
                                                      predicate: NSPredicate,
                                                      sortedKey: String,
                                                      isAssending: Bool,
                                                      fromIndex: Int,
                                                      pageSize: Int) -> Array<Object>? {
        guard let results = queryWithSorted(object: object,
                                         predicate: predicate,
                                         sortedKey: sortedKey,
                                     isAssending: isAssending) else {
            return nil
        }
        var resultsArray = Array<Object>()
        if results.count <= pageSize * (fromIndex - 1) || fromIndex <= 0 {
            return resultsArray
        }
        if results.count > 0 {
            for i in pageSize * (fromIndex - 1)...(fromIndex * pageSize - 1) {
                resultsArray.append(results[i])
            }
        }
        return resultsArray
    }
}


extension ZFRealmManager{
    /// 查询某个对象数据
    /// - Parameter object: 对象类型
    /// - Returns: 返回查询对象数组
    private static func queryWithType(object: Object.Type) -> Results<Object>? {
        guard let realm = shared.realm else {
            return nil
        }
        return realm.objects(object)
    }
    
    // MARK: 根据条件查询数据
    /// 根据条件查询数据
    /// - Parameters:
    ///   - object: 对象类型
    ///   - predicate: 查询条件
    /// - Returns: 返回查询对象数组
    private static func queryWith(object: Object.Type,
                               predicate: NSPredicate) -> Results<Object>? {
        guard let realm = shared.realm else {
            return nil
        }
        return realm.objects(object).filter(predicate)
    }
    
    // MARK: 带排序条件查询
    /// 带排序条件查询
    /// - Parameters:
    ///   - object: 对象类型
    ///   - predicate: 查询条件
    ///   - sortedKey: 排序的键
    ///   - isAssending: 升序还是降序，默认升序
    /// - Returns: 返回查询对象数组
    private static func queryWithSorted(object: Object.Type,
                                     predicate: NSPredicate,
                                     sortedKey: String,
                                   isAssending: Bool = true) -> Results<Object>? {
        guard let realm = shared.realm else {
            return nil
        }
        return realm.objects(object).filter(predicate)
            .sorted(byKeyPath: sortedKey, ascending: isAssending)
    }
    
    // MARK: 查询结果转Array<Object>
    /// 查询结果转Array<Object>
    /// - Parameter results: 查询结果
    /// - Returns: 返回Array<Object>
    private static func resultsToObjectList(results: Results<Object>) -> [Object] {
        var resultsArray = [Object]()
        if results.count > 0 {
            for i in 0...(results.count - 1) {
                resultsArray.append(results[i])
            }
        }
        return resultsArray
    }
}
